
import { log, error, warn } from "@/util/tio";
import { ungzip } from "pako";
import cmds, { cmdStr_func_map, cmdStr_name_map, CMD_LEN } from "./cmds";

/**
 * 注册命令码
 * @param cmdName 
 * @param cmdVal 
 * @param handler 
 */
const r = (cmdName, cmdVal: Number, handler: Function) => {
    cmds[cmdName] = [cmdVal, handler]
    let cmdStr = cmdFunc.format(cmdVal);
    cmdStr_name_map[cmdStr] = cmdName;
    if (handler) {
        cmdStr_func_map[cmdStr] = handler;
    }
}
/**
 *  register('SomeOtherResp', 5656, ({ tws, bodyObj, bodyStr, cmdName, cmdStr, event }) => {
        log({ tws, bodyObj, bodyStr, cmdName, cmdStr, event })
    })
 * 注册命令及元数据
 * @param cmdName 
 * @param cmdVal 
 * @param handler 
 */
export const register = (cmdName, cmdVal: Number, handler: Function) => {
    if (cmds[cmdName]) {
        error(`${cmdName} has registered`);
        return
    }
    r(cmdName, cmdVal, handler)
}

/** 初始化时，需要调一下: cmdFunc.init(); */
export const cmdFunc = {
    /** 格式化命令码：1 -> "00001";  -1 -> "-0001" */
    format: (cmdVal) => (cmdVal + "").padStart(cmdVal < 0 ? CMD_LEN - 1 : CMD_LEN, "0"),
    /** 解析命令码："00001" -> 1; "-0001" -> -1 */
    parse: (cmdStr) => parseInt(cmdStr),
    /** 运行命令码：执行命令码对应的handler函数 */
    dispatch: (tws, bodyObj, bodyStr, cmdStr, event) => {
        let cmdName = cmdStr_name_map[cmdStr]
        if (!cmdName) {
            warn(`can not find cmd for cmdStr[${cmdStr}]`)
            return
        }
        let cmdMeta = cmds[cmdName]
        if (cmdMeta && cmdMeta.length == 2) {
            cmdMeta[1]({ tws, bodyObj, bodyStr, cmdName, cmdStr, event });
        } else {
            warn(`can not find function for cmdName[${cmdName}]`)
        }
    }
}
let init = () => {
    let entry = Object.entries(cmds)
    log(`init cmds`)
    for (const [key, value] of entry) {
        let cmdVal = value[0];
        let cmdStr = cmdFunc.format(cmdVal);
        cmdStr_name_map[cmdStr] = key;
        if (value.length == 2) {
            cmdStr_func_map[cmdStr] = value[1];
        }
    }
}
init()

/** 
 * 发送消息
 * send(cmd.WxHandshakeReq, {name:"talent.tan"})
 */
export const send = (tws, cmdMeta, bodyObj?) => {
    let cmdVal = cmdMeta[0];
    let cmdStr = cmdFunc.format(cmdVal);
    let str = cmdStr;
    if (bodyObj) {
        str = cmdStr + JSON.stringify(bodyObj);
    }
    let uint8array = new TextEncoder().encode(str);
    tws.send(uint8array.buffer);
}

export const onmessage = (tws, ws, data, event) => {
    let firstbyte = new Uint8Array(data, 0, 2);
    let firstchar = new TextDecoder('utf-8').decode(firstbyte);
    let uint8array
    if (firstchar.indexOf('x') != -1) {
        let zipedUint8array = new Uint8Array(data, 2);
        uint8array = ungzip(zipedUint8array);
    } else {
        uint8array = new Uint8Array(data);
    }

    let strData = new TextDecoder('utf-8').decode(uint8array);

    if (!strData || strData.length < CMD_LEN) {
        error('data wrong, the data length must be >= ' + CMD_LEN, strData);
        return;
    }

    let cmdStr = strData.substr(0, CMD_LEN);

    let bodyStr, bodyObj
    if (strData.length > CMD_LEN) {
        bodyStr = strData.substr(CMD_LEN);
        try {
            bodyObj = JSON.parse(bodyStr);
        } catch (err) {
            error(`can not parse to object, cmdStr[${cmdStr}], bodyStr[${bodyStr}]`);
            return;
        }
    }
    cmdFunc.dispatch(tws, bodyObj, bodyStr, cmdStr, event)
}
